/**
 *
 */
package com.fita.webpay.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dao;
import com.fita.webpay.dao.PaymentDao;
import com.fita.webpay.entity.PayEvent;
import com.fita.webpay.entity.PayStatus;
import com.fita.webpay.entity.PaymentContext;
import com.fita.webpay.entity.PaymentRound;
import com.fita.webpay.entity.prepare.PrepareRequest;
import com.fita.webpay.service.PaymentService;

/**
 * @author downpour
 *
 */
@Service("paymentService")
public class PaymentServiceImpl implements PaymentService {

    private static final Logger logger = LoggerFactory.getLogger(PaymentServiceImpl.class);

    @Dao
    private PaymentDao paymentDao;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;

    /* (non-Javadoc)
     * @see com.continental.payment.service.PaymentService#prepareContext(com.continental.payment.entity.PrepareRequest)
     */
    public PaymentContext prepareContext(PrepareRequest prepareRequest) {

        String requestNo = prepareRequest.getRequestNo();
        String orderNo = prepareRequest.getOrderNo();

        // 1. create new payment round anyway
        this.createRound(requestNo, orderNo, PayEvent.REQUEST, prepareRequest.getRemoteIp());

        // 2. check whether payment context exists
        PaymentContext paymentContext = paymentDao.get(requestNo);
        
        if(paymentContext == null) {
            
            paymentContext = new PaymentContext(prepareRequest);
            
            genericDaoSupport.save(paymentContext);
            
        } else {
            
            logger.warn("#preparePaymentContext - PaymentContext[ requestNo: {}, orderNo: {} ] already exists.", prepareRequest.getRequestNo(), prepareRequest.getOrderNo());
            
        }
        
        return paymentContext;
    }

    /* (non-Javadoc)
     * @see com.continental.payment.service.PaymentService#loadContext(java.lang.String)
     */
    public PaymentContext loadContext(String outTradeNo) {
        return paymentDao.get(outTradeNo);
    }
    
    /* (non-Javadoc)
     * @see com.continental.payment.service.PaymentService#paid(com.continental.payment.entity.PaymentContext, java.lang.String)
     */
    public boolean paid(PaymentContext paymentContext, String transactionCode) {
        
        PayStatus status = paymentContext.getStatus();
        
        if (status != null && status.isWaiting()) {  // Only do logic when payment context status is still `WATING`.
            
            // Update payment context
            paymentDao.finish(paymentContext.getId(), transactionCode);
            
            // Create finish payment round
            String token = paymentContext.getToken();
            String orderNo = paymentContext.getOrderCode();
            this.createRound(token, orderNo, PayEvent.PAID, null);
        
            return true;
            
        }
        
        logger.warn("#paid - Current payment context [{}] with order code [{}] has the status of [{}].", paymentContext.getId(), paymentContext.getOrderCode(), status);
        
        return false;
        
    }

    /* (non-Javadoc)
     * @see com.continental.payment.service.PaymentService#createRound(java.lang.String, java.lang.String, com.continental.payment.entity.PayEvent, java.lang.String)
     */
    public void createRound(String requestNo, String orderNo, PayEvent event, String clientIp) {
        
        // create payment round by request_no, order_no, event and client_ip
        PaymentRound paymentRound = new PaymentRound(requestNo, orderNo, event, clientIp);
        
        genericDaoSupport.save(paymentRound);
        
    }
    
}
